import importlib
import json
from django.conf import settings
from utils.base_response import BaseResponse
from ProjectTool.common_tool.db_tool.db_conf import DB_TYPES
from ProjectTool.common_tool.in_out_parameter import InParameter, FuncParameter, StepsData
from ProjectTool.common_tool.assert_tool import AssertTool


class ParsingStepsRealizeWebData:
    def __init__(self, steps_realize_obj, data_warehouse, steps_data, steps_realize_dict, driver=None,
                 driver_status=None, page_class_obj=None):
        self.res = BaseResponse()
        self.page_class_obj = page_class_obj
        self.data_warehouse = data_warehouse
        self.steps_data = steps_data
        self.steps_realize_dict = steps_realize_dict
        self.driver = driver
        self.driver_status = driver_status
        self.steps_realize_obj = steps_realize_obj  # 步骤明细
        self.obj_key = None  # 对象key
        self.body_db_info = None  # 入参数据库信息
        self.assert_db_info = None  # 断言数据库信息
        self.environment_into = None  # 端口信息
        self.into_sql = None  # 入参sql
        self.assert_sql = None  # 断言sql
        self.into_sql_data = None  # sql入参执行结果
        self.assert_sql_data = None  # sql出参执行结果
        self.page_out_data = None  # 页面数据
        self.into_data = None  # 入参数据
        self.out_data = None  # 出参数据
        self.assert_data = None  # 断言数据
        self.result_data = None  # 对比结果
        self.results = 3  # 执行状态
        self.show_status = False  # 显示正确结果

    # 保存当前参数
    def set_steps_realize_obj(self):
        def json_dumps(value, cls):
            if not value:
                return None
            return json.dumps(value, ensure_ascii=False) if isinstance(value, cls) else str(value)

        self.steps_realize_obj.into_sql_pull = self.into_sql
        self.steps_realize_obj.assert_sql_pull = self.assert_sql
        self.steps_realize_obj.into_data = json_dumps(self.into_data, dict)
        self.steps_realize_obj.out_data = json_dumps(self.out_data, dict)
        self.steps_realize_obj.assert_data = json_dumps(self.assert_data, dict)
        self.steps_realize_obj.result_data = json_dumps(self.result_data, dict)
        self.steps_realize_obj.page_out_data = json_dumps(self.page_out_data, dict)
        self.steps_realize_obj.results = self.results
        self.steps_realize_obj.save()

    # 明细数据
    def get_steps_realize_data(self):
        self.steps_realize_dict[self.obj_key] = {  # 明细数据
            'body_db_info': self.body_db_info,
            'assert_db_info': self.assert_db_info,
            'environment_into': self.environment_into,
            'into_sql': self.into_sql,
            'assert_sql': self.assert_sql,
            'into_sql_data': self.into_sql_data,
            'assert_sql_data': self.assert_sql_data,
            'into_data': self.into_data,
            'out_data': self.out_data,
            'page_out_data': self.page_out_data,
            'assert_data': self.assert_data,
            'result_data': self.result_data,
            'results': self.results,
            'obj_key': self.obj_key
        }

    def json_loads(self, value):
        try:
            value = json.loads(value)
        except Exception as e:
            self.res.status = 1
            self.res.msg = '数据转行字典失败！'
            self.res.error = str(e.args)
        return value

    # 数据交换
    def get_parsing_data(self, out_data):
        self.get_steps_realize_data()
        if out_data:
            func_obj = FuncParameter(out_data)
            func_obj.run()
            if func_obj.res.status:
                self.res = func_obj.res
            out_data = func_obj.obj_data
            if not self.res.status:
                out_data = self.json_loads(out_data)
                if not self.res.status:
                    out_obj = StepsData(out_data, self.data_warehouse, self.steps_data)
                    out_obj.run()
                    out_data = out_obj.out_data
                    if out_obj.res.status:
                        self.res = out_obj.res
        return out_data

    # 导入页面对象模块
    def get_class(self):
        project_key = self.steps_realize_obj.project.project_key
        module_key = self.steps_realize_obj.module.module_key
        module_page_key = self.steps_realize_obj.module_page.module_page_key
        # 'WEBTest.common.page_object.{project}.{module}.{pyfile}'
        module_obj = importlib.import_module(
            '..{class_name}'.format(class_name=module_page_key),
            'ProjectTool.WebTool.page_object.{project}.{module}.{pyfile}'.format(
                project=project_key,
                module=module_key,
                pyfile=module_page_key
            )
        )
        class_obj = getattr(module_obj, module_page_key)
        return class_obj

    # 获取函数
    def get_func(self, obj):
        return getattr(obj, self.steps_realize_obj.selenium_func.func_name)

    # 获取obj_key
    def get_obj_key(self):
        self.obj_key = self.steps_realize_obj.obj_key

    # 获取数据库信息
    def get_db_info(self):
        if self.res.status: return
        body_db_obj = self.steps_realize_obj.selenium_func.sql_detail_body
        assert_db_obj = self.steps_realize_obj.selenium_func.sql_detail_assert

        def db_info(obj):
            if obj:
                my_obj = obj.database
                db_types = settings.MODELS_CHOICES['database']['db_type']
                db_type = [db[1] for db in db_types if db[0] == my_obj.db_type][0]
                return {
                    'db_info': {
                        'db': my_obj.db_name,
                        'host': my_obj.db_ip,
                        'port': my_obj.db_port,
                        'user': my_obj.db_user,
                        'password': my_obj.db_password,
                        'charset': 'utf8'
                    },
                    'db_type': db_type
                }

        self.body_db_info = db_info(body_db_obj)
        self.assert_db_info = db_info(assert_db_obj)

    # 获取环境信息
    def get_environment_into(self):
        if self.res.status: return
        environment_obj = self.steps_realize_obj.project.environment
        self.environment_into = {
            'env_protocol': environment_obj.env_protocol,
            'env_ip': environment_obj.env_ip,
            'env_port': environment_obj.env_port,
            'env_domain': environment_obj.env_domain,  # 域名
            'env_title': environment_obj.env_title,
            'token': environment_obj.token,
            'local_storage': environment_obj.local_storage,
            'session_storage': environment_obj.session_storage,
        }

    # 获取sql
    def get_sql(self):
        into_sql_push = self.steps_realize_obj.into_sql_push  # web查询sql入参模板
        assert_sql_push = self.steps_realize_obj.assert_sql_push  # web断言sql入参
        if (self.body_db_info and not into_sql_push) or (self.assert_db_info and not assert_sql_push):
            self.res.status = 1
            self.res.msg = '请完成sql模板'
            return
        into_sql_data = self.get_parsing_data(into_sql_push)
        assert_sql_data = self.get_parsing_data(assert_sql_push)
        body_db_obj = self.steps_realize_obj.selenium_func.sql_detail_body
        assert_db_obj = self.steps_realize_obj.selenium_func.sql_detail_assert
        into_sql = body_db_obj.sql_template if body_db_obj else None
        assert_sql = assert_db_obj.sql_template if assert_db_obj else None
        self.into_sql = InParameter(into_sql_data, into_sql).run() if into_sql else None
        self.assert_sql = InParameter(assert_sql_data, assert_sql).run() if assert_sql else None
        self.get_steps_realize_data()  # 更新数据

    # 获取self.into_sql_data
    def get_into_sql_data(self):
        if self.res.status: return
        if self.body_db_info:
            db_info = self.body_db_info.get('db_info')
            db_class = DB_TYPES.get(self.body_db_info.get('db_type'))
            if self.into_sql:
                db_obj = db_class(**db_info)
                self.into_sql_data = db_obj.execute_select(self.into_sql)  # 查询sql
                db_obj.close()
                res = db_obj.res
                if res.status:
                    self.res = res
        self.get_steps_realize_data()  # 更新数据

    # 获取self.assert_db_info
    def get_assert_sql_data(self):
        if self.res.status: return
        if self.assert_db_info:
            db_info = self.assert_db_info.get('db_info')
            db_class = DB_TYPES.get(self.assert_db_info.get('db_type'))
            if self.assert_sql:
                db_obj = db_class(**db_info)
                self.assert_sql_data = db_obj.execute_select(self.assert_sql)  # 查询sql
                db_obj.close()
                res = db_obj.res
                if res.status:
                    self.res = res
        self.get_steps_realize_data()  # 更新数据

    # 获取入参数据
    def get_into_data(self):
        if self.res.status: return
        template_data = self.steps_realize_obj.into_template
        template_data = self.get_parsing_data(template_data)
        self.into_data = template_data
        self.get_steps_realize_data()  # 更新数据

    # 获取断言数据
    def get_assert_data(self):
        if self.res.status: return
        template_data = self.steps_realize_obj.assert_template
        template_data = self.get_parsing_data(template_data)
        self.assert_data = template_data
        self.get_steps_realize_data()  # 更新数据

    # 出参数据:被校验数据，一般来自于数据库 或者页面数据
    def get_out_data(self):
        if self.res.status: return
        template_data = self.steps_realize_obj.out_template
        template_data = self.get_parsing_data(template_data)
        self.out_data = template_data
        self.get_steps_realize_data()  # 更新数据

    # 数据对比结果
    def get_result_data(self):
        if self.res.status:
            self.result_data = self.res.dict
            return
        if not self.assert_data:
            self.assert_data = {}
        if not self.out_data:
            self.out_data = {}
        tb = AssertTool(self.assert_data, self.out_data, self.show_status)
        tb.run()
        self.result_data = tb.dict()
        self.res = tb.res
        self.get_steps_realize_data()  # 更新数据

    def exe_func(self, func, data):
        if self.res.status: return
        try:
            if isinstance(data, dict):
                self.page_out_data = func(**data)
            else:
                self.page_out_data = func(data)
        except Exception as e:
            self.res.status = 1
            self.res.msg = '函数执行异常！'
            self.res.error = str(e.args)

    # 运行
    def run(self):
        try:
            class_obj = self.get_class()
            self.get_environment_into()
            self.get_db_info()
            if isinstance(self.page_class_obj, class_obj):
                obj = self.page_class_obj
            else:
                obj = class_obj(
                    http_status=self.environment_into.get('env_protocol'),
                    host=self.environment_into.get('env_ip'),
                    port=self.environment_into.get('env_port'),
                    domain=self.environment_into.get('env_domain'),
                    local_storage=self.environment_into.get('local_storage'),
                    session_storage=self.environment_into.get('session_storage'),
                    driver=self.driver,
                    driver_status=self.driver_status
                )
                obj.run()
                self.driver = obj.driver
                obj.permission_information()
                self.page_class_obj = obj
            func = self.get_func(obj)
            self.get_obj_key()
            self.get_sql()  # 获取sql
            self.get_into_sql_data()  # 获取入参sql执行数据
            self.get_into_data()
            self.exe_func(func, self.into_data)
            self.get_assert_sql_data()  # 获取断言sql执行数据
            self.get_assert_data()  # 获取断言数据
            self.get_out_data()  # 获取被校验数据
            self.get_result_data()
            if self.res.status:
                self.results = 2
            else:
                self.results = 1
        except Exception as e:
            self.results = 4
            self.res.status = 1
            self.res.msg = 'web明细执行失败'
            self.res.error = str(e.args)
            # raise e
        self.set_steps_realize_obj()  # 保存数据
        return self.res

    # # 运行
    # def run(self):
    #     class_obj = self.get_class()
    #     self.get_environment_into()
    #     self.get_db_info()
    #     if isinstance(self.page_class_obj, class_obj):
    #         obj = self.page_class_obj
    #     else:
    #         obj = class_obj(
    #             http_status=self.environment_into.get('env_protocol'),
    #             host=self.environment_into.get('env_ip'),
    #             port=self.environment_into.get('env_port'),
    #             domain=self.environment_into.get('env_domain'),
    #             local_storage=self.environment_into.get('local_storage'),
    #             session_storage=self.environment_into.get('session_storage'),
    #             driver=self.driver,
    #             driver_status=self.driver_status
    #         )
    #         obj.run()
    #         self.driver = obj.driver
    #         obj.permission_information()
    #         self.page_class_obj = obj
    #     func = self.get_func(obj)
    #     print('self.driver5:', self.driver)
    #     # self.driver = obj.driver
    #     self.get_obj_key()
    #     self.get_sql()  # 获取sql
    #     self.get_into_sql_data()  # 获取入参sql执行数据
    #     self.get_into_data()
    #     self.exe_func(func, self.into_data)
    #     self.get_assert_sql_data()  # 获取断言sql执行数据
    #     self.get_assert_data()  # 获取断言数据
    #     self.get_out_data()  # 获取被校验数据
    #     self.get_result_data()
    #     if self.res.status:
    #         self.results = 2
    #     else:
    #         self.results = 1
    #     self.set_steps_realize_obj()  # 保存数据
    #     return self.res
